#if !defined(RulesHeader)
#define RulesHeader

#include <map>
#include <tr1/unordered_map>
#include <vector>

#include "bytecode.h"
#include "node.h"
#include "prototype.h"

class RulesIterator {
public:
  virtual ~RulesIterator () {
  }

  virtual Node *operator * () = 0; // Get current rule we pointing at

  virtual void next () = 0; // Advance pointer

  virtual bool valid () = 0; // Not go out of range yet?
};

class Rules {
public:
  Rules () :
    nNamelessRules (0), bytecodeEnabled (false) {
  }

  void assertz (pNode&);
  void retract (Node*);

  void buildIndex (); // Update all entries after some inserts/deletes

  void updateCounts () { // Statistics that speed up inferencing
    nNamelessRules = indexByPrototype.count (Prototype ());
  }

  RulesIterator *createIterator (Node &clause) {
    return createIterator (Prototype::get (clause));
  }

  RulesIterator *createIterator (const Prototype &proto) {

    // Indexing won't work if
    // 1. There are clauses without index, or
    // 2. The search clause cannot be indexed
    if(nNamelessRules || proto.type == Reference::ID)
      return createIteratorForAll (); // Do not use indexing
    else
      return createIteratorForPrototype (proto);
  }

  // Iterators for different traversal methods (i.e. indexed or not)

  // Total traversal in a rules database
  RulesIterator *createIteratorForAll ();

  // Only traverse rules with specified prototype
  RulesIterator *createIteratorForPrototype (const Prototype &proto);

  Snippet &findSnippet (Prototype&);
  Snippet &putSnippet (const Prototype&, const Snippet&);

  // Tautologies. Uses pNode to hold the 'primary' copy to avoid being recycled
  std::vector<pNode> rules;

  // This is actually a Red-black tree. We like its O(logN) performance
  typedef std::tr1::unordered_map<Prototype, std::vector<Node*> > Index;
  Index indexByPrototype; // Uses clause identifier as index

  int nNamelessRules; // Count the rules without clause names

  // Cache the compiled rules
  bool bytecodeEnabled;
  typedef std::tr1::unordered_map<Prototype, Snippet> Snippets;
  Snippets snippets;

  ReadWriteLock lock;
};

#endif
